// 版权所有2012 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:构建种族

package runtime

import (
	"internal/abi"
	"unsafe"
)

// 公共种族检测API，使用-race呈现iff构建。

func RaceRead(addr unsafe.Pointer)
func RaceWrite(addr unsafe.Pointer)
func RaceReadRange(addr unsafe.Pointer, len int)
func RaceWriteRange(addr unsafe.Pointer, len int)

func RaceErrors() int {
	var n uint64
	racecall(&__tsan_report_count, uintptr(unsafe.Pointer(&n)), 0, 0, 0)
	return int(n)
}

// go:nosplit 

// Race Acquire/Race Release/Race Release合并建立在goroutines之间的关系
// 。这些信息会通知竞态检测器由于某种原因无法看到的实际同步
// （例如，代码中的RaceDisable/RaceEnable 
// 部分中的同步）。
// RaceAcquire与之前的
// RaceReleaseMerge on addr建立了发生在之前的关系，直到并包括addr上的最后一个RaceRelease。
// 就C内存模型（C11§5.1.2.4，§7.17.3）而言，
// RaceAcquire相当于原子负载（内存顺序获取）。
func RaceAcquire(addr unsafe.Pointer) {
	raceacquire(addr)
}

// go:nosplit 

// RaceRelease在addr上执行释放操作，
// 可以在addr上与后面的RaceAcquire同步。
// 
// 就C内存模型而言，RaceRelease相当于
// 原子存储（内存顺序释放）。
func RaceRelease(addr unsafe.Pointer) {
	racerelease(addr)
}

// go:nosplit 

// RaceReleaseMerge类似于RaceRelease，但也建立了一个before 
// 与addr上的先前RaceRelease或RaceReleaseMerge的关系。
// 
// 就C内存模型而言，RaceReleaseMerge相当于
// 原子交换（内存顺序释放）。
func RaceReleaseMerge(addr unsafe.Pointer) {
	racereleasemerge(addr)
}

// go:nosplit 

// RaceDisable禁用当前goroutine中的种族同步事件处理。
// 使用RaceEnable重新启用处理。RaceDisable/RaceEnable可以嵌套。
// 非同步事件（内存访问、函数进入/退出）仍会影响
// 竞赛检测器。
func RaceDisable() {
	_g_ := getg()
	if _g_.raceignore == 0 {
		racecall(&__tsan_go_ignore_sync_begin, _g_.racectx, 0, 0, 0)
	}
	_g_.raceignore++
}

// go:nosplit 

// RaceEnable重新启用当前goroutine中的赛事处理。
func RaceEnable() {
	_g_ := getg()
	_g_.raceignore--
	if _g_.raceignore == 0 {
		racecall(&__tsan_go_ignore_sync_end, _g_.racectx, 0, 0, 0)
	}
}

// 运行时的专用接口。

const raceenabled = true

// 对于所有接受callerpc和pc的函数，
// callerpc是调用此函数的函数的返回pc，
// pc是调用此函数的函数的开始pc。
func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) {
	kind := t.kind & kindMask
	if kind == kindArray || kind == kindStruct {
		// 对于复合对象，我们必须读取每个地址
		// 因为任何子对象都可能发生写操作。
		racereadrangepc(addr, t.size, callerpc, pc)
	} else {
		// 对于非复合对象，我们只能读取起始地址
		// 地址，因为任何写入都必须写入第一个字节。
		racereadpc(addr, callerpc, pc)
	}
}

func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) {
	kind := t.kind & kindMask
	if kind == kindArray || kind == kindStruct {
		// 对于复合对象，我们必须写入每个地址
		// 因为写入可能发生在任何子对象上。
		racewriterangepc(addr, t.size, callerpc, pc)
	} else {
		// 对于非复合对象，我们可以只写入起始地址，因为任何写入都必须写入第一个字节。
		racewritepc(addr, callerpc, pc)
	}
}

// go:noescape 
func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)

// go:noescape 
func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)

type symbolizeCodeContext struct {
	pc   uintptr
	fn   *byte
	file *byte
	line uintptr
	off  uintptr
	res  uintptr
}

var qq = [...]byte{'?', '?', 0}
var dash = [...]byte{'-', 0}

const (
	raceGetProcCmd = iota
	raceSymbolizeCodeCmd
	raceSymbolizeDataCmd
)

// 从C回调到go，在g0上运行。
func racecallback(cmd uintptr, ctx unsafe.Pointer) {
	switch cmd {
	case raceGetProcCmd:
		throw("should have been handled by racecallbackthunk")
	case raceSymbolizeCodeCmd:
		raceSymbolizeCode((*symbolizeCodeContext)(ctx))
	case raceSymbolizeDataCmd:
		raceSymbolizeData((*symbolizeDataContext)(ctx))
	default:
		throw("unknown command")
	}
}

// 代码读取ctx。pc并用
// 填充*ctx的其余部分。
// 
// 竞赛检测器已从pc中减去1，因此它们指向最后一个
// 字节的调用指令（包括对runtime.racewite和friends的调用）。
// 
// 如果传入的pc是内联函数的一部分，*ctx将填充有关内联函数的信息，并在返回ctx时填充。pc被设置为逻辑包含函数中的pc。（竞赛检测器应该再次调用该pc的
// 函数。）
// 
// 如果传入的pc不是内联函数的一部分，则返回的pc不变。
func raceSymbolizeCode(ctx *symbolizeCodeContext) {
	pc := ctx.pc
	fi := findfunc(pc)
	f := fi._Func()
	if f != nil {
		file, line := f.FileLine(pc)
		if line != 0 {
			if inldata := funcdata(fi, _FUNCDATA_InlTree); inldata != nil {
				inltree := (*[1 << 20]inlinedCall)(inldata)
				for {
					ix := pcdatavalue(fi, _PCDATA_InlTreeIndex, pc, nil)
					if ix >= 0 {
						if inltree[ix].funcID == funcID_wrapper {
							// 忽略包装
							// 备份到“调用者”中的指令。
							pc = f.Entry() + uintptr(inltree[ix].parentPc)
							continue
						}
						ctx.pc = f.Entry() + uintptr(inltree[ix].parentPc) // “调用者”pc 
						ctx.fn = cfuncnameFromNameoff(fi, inltree[ix].func_)
						ctx.line = uintptr(line)
						ctx.file = &bytes(file)[0] // 假设NUL终止
						ctx.off = pc - f.Entry()
						ctx.res = 1
						return
					}
					break
				}
			}
			ctx.fn = cfuncname(fi)
			ctx.line = uintptr(line)
			ctx.file = &bytes(file)[0] // 假设NUL终止
			ctx.off = pc - f.Entry()
			ctx.res = 1
			return
		}
	}
	ctx.fn = &qq[0]
	ctx.file = &dash[0]
	ctx.line = 0
	ctx.off = ctx.pc
	ctx.res = 1
}

type symbolizeDataContext struct {
	addr  uintptr
	heap  uintptr
	start uintptr
	size  uintptr
	name  *byte
	file  *byte
	line  uintptr
	res   uintptr
}

func raceSymbolizeData(ctx *symbolizeDataContext) {
	if base, span, _ := findObject(ctx.addr, 0, 0); base != 0 {
		ctx.heap = 1
		ctx.start = base
		ctx.size = span.elemsize
		ctx.res = 1
	}
}

// 通过运行时调用Race运行时函数。CDEFG
var __tsan_init byte

var __tsan_fini byte

var __tsan_proc_create byte

var __tsan_proc_destroy byte

var __tsan_map_shadow byte

// go:linkname _tsan_finalizer_goroutine__目前，最后一个最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最终的最后的最后的最后的最后的最后的最后的最后的最后的最后的最后的最后的最后的最后的最后的最后的一次的一次的一次的一次的
var __tsan_finalizer_goroutine byte

var __tsan_go_start byte

var __tsan_go_end byte

var __tsan_malloc byte

var __tsan_free byte

var __tsan_acquire byte

var __tsan_release byte

var __tsan_release_acquire byte

var __tsan_release_merge byte

var __tsan_go_ignore_sync_begin byte

var __tsan_go_ignore_sync_end byte

// go:linkname _tsan_report_count _tsan_report_count 
var __tsan_report_count byte

// 模仿cmd/cgo的做法。中文参考双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语政府政府政府政府政府政府政府政府政府政府政府政府
// go:cgo_import_static__4.6.6
// go:cgo\U导入\U静态__tsan_release_merge_
// go:cgo_import_static uu tsan_go_ignore_sync_begin 
// go:cgo_import_static u tsan_go_ignore_sync_end 
// go:cgo:cgo_import_static u static u tsan_ureport_ucount 

// go:cgo_import_static_tsan_func_enter目前，中国的出口。中国的出口。中国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国的外国go:cgo_import_static___tsan_go_atomic32_exchange 


// 全局数据的开始/结束（数据+bss）。
var racedatastart uintptr
var racedataend uintptr

// race_amd64堆的开始/结束。s 
var racearenastart uintptr
var racearenaend uintptr

func racefuncenter(callpc uintptr)
func racefuncenterfp(fp uintptr)
func racefuncexit()
func raceread(addr uintptr)
func racewrite(addr uintptr)
func racereadrange(addr, size uintptr)
func racewriterange(addr, size uintptr)
func racereadrangepc1(addr, size, pc uintptr)
func racewriterangepc1(addr, size, pc uintptr)
func racecallbackthunk(uintptr)

// racecall允许从C race运行时
// 使用最多4个uintpttr参数调用任意函数fn。
func racecall(fn *byte, arg0, arg1, arg2, arg3 uintptr)

// 检查地址是否有阴影（即堆或数据/bss）
// go:nosplit 
func isvalidaddr(addr unsafe.Pointer) bool {
	return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend ||
		racedatastart <= uintptr(addr) && uintptr(addr) < racedataend
}

// go:nosplit 
func raceinit() (gctx, pctx uintptr) {
	// 初始化libc需要cgo，这是竞赛运行时
	if !iscgo {
		throw("raceinit: race build must use cgo")
	}

	racecall(&__tsan_init, uintptr(unsafe.Pointer(&gctx)), uintptr(unsafe.Pointer(&pctx)), abi.FuncPCABI0(racecallbackthunk), 0)

	// 将数据段舍入页面边界，因为它在mmap（）中使用。
	start := ^uintptr(0)
	end := uintptr(0)
	if start > firstmoduledata.noptrdata {
		start = firstmoduledata.noptrdata
	}
	if start > firstmoduledata.data {
		start = firstmoduledata.data
	}
	if start > firstmoduledata.noptrbss {
		start = firstmoduledata.noptrbss
	}
	if start > firstmoduledata.bss {
		start = firstmoduledata.bss
	}
	if end < firstmoduledata.enoptrdata {
		end = firstmoduledata.enoptrdata
	}
	if end < firstmoduledata.edata {
		end = firstmoduledata.edata
	}
	if end < firstmoduledata.enoptrbss {
		end = firstmoduledata.enoptrbss
	}
	if end < firstmoduledata.ebss {
		end = firstmoduledata.ebss
	}
	size := alignUp(end-start, _PageSize)
	racecall(&__tsan_map_shadow, start, size, 0, 0)
	racedatastart = start
	racedataend = start + size

	return
}

var raceFiniLock mutex

// go:nosplit 
func racefini() {
	// racefini（）只能调用一次以避免竞争。
	// 这最终（通过u tsan_fini）调用C.exit，如果多次调用，它将具有未定义的行为。如果锁是
	// 已被保持，则假定第一个调用方退出程序
	// 因此其他调用可以永久挂起而不会出现问题。
	lock(&raceFiniLock)
	// 我们正在输入可能在
	// Windows上调用ExitProcess的外部代码。go:nosplit 
	osPreemptExtEnter(getg().m)
	racecall(&__tsan_fini, 0, 0, 0, 0)
}

func raceproccreate() uintptr {
	var ctx uintptr
	racecall(&__tsan_proc_create, uintptr(unsafe.Pointer(&ctx)), 0, 0, 0)
	return ctx
}

func raceprocdestroy(ctx uintptr) {
	racecall(&__tsan_proc_destroy, ctx, 0, 0, 0)
}

// go:nosplit 
func racemapshadow(addr unsafe.Pointer, size uintptr) {
	if racearenastart == 0 {
		racearenastart = uintptr(addr)
	}
	if racearenaend < uintptr(addr)+size {
		racearenaend = uintptr(addr) + size
	}
	racecall(&__tsan_map_shadow, uintptr(addr), size, 0, 0)
}

// go:nosplit 
func racemalloc(p unsafe.Pointer, sz uintptr) {
	racecall(&__tsan_malloc, 0, 0, uintptr(p), sz)
}

// go:nosplit 
func racefree(p unsafe.Pointer, sz uintptr) {
	racecall(&__tsan_free, uintptr(p), sz, 0, 0)
}

// go:nosplit 
func racegostart(pc uintptr) uintptr {
	_g_ := getg()
	var spawng *g
	if _g_.m.curg != nil {
		spawng = _g_.m.curg
	} else {
		spawng = _g_
	}

	var racectx uintptr
	racecall(&__tsan_go_start, spawng.racectx, uintptr(unsafe.Pointer(&racectx)), pc, 0)
	return racectx
}

// go nosplit 
func racegoend() {
	racecall(&__tsan_go_end, getg().racectx, 0, 0, 0)
}

func racectxend(racectx uintptr) {
	racecall(&__tsan_go_end, racectx, 0, 0, 0)
}

// go nosplit 
func racewriterangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
	_g_ := getg()
	if _g_ != _g_.m.curg {
		// 没意思。
		return
	}
	if callpc != 0 {
		racefuncenter(callpc)
	}
	racewriterangepc1(uintptr(addr), sz, pc)
	if callpc != 0 {
		racefuncexit()
	}
}

// go:nosplit 
func racereadrangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
	_g_ := getg()
	if _g_ != _g_.m.curg {
		// 调用来自运行在g0/gsignal上的go代码的手动检测。
		// 没意思。
		return
	}
	if callpc != 0 {
		racefuncenter(callpc)
	}
	racereadrangepc1(uintptr(addr), sz, pc)
	if callpc != 0 {
		racefuncexit()
	}
}

// go:nosplit 
func raceacquire(addr unsafe.Pointer) {
	raceacquireg(getg(), addr)
}

// go:nosplit 
func raceacquireg(gp *g, addr unsafe.Pointer) {
	if getg().raceignore != 0 || !isvalidaddr(addr) {
		return
	}
	racecall(&__tsan_acquire, gp.racectx, uintptr(addr), 0, 0)
}

// go:nosplit 
func raceacquirectx(racectx uintptr, addr unsafe.Pointer) {
	if !isvalidaddr(addr) {
		return
	}
	racecall(&__tsan_acquire, racectx, uintptr(addr), 0, 0)
}

// go:nosplit 
func racerelease(addr unsafe.Pointer) {
	racereleaseg(getg(), addr)
}

// go nosplit 
func racereleaseg(gp *g, addr unsafe.Pointer) {
	if getg().raceignore != 0 || !isvalidaddr(addr) {
		return
	}
	racecall(&__tsan_release, gp.racectx, uintptr(addr), 0, 0)
}

// go nosplit 
func racereleaseacquire(addr unsafe.Pointer) {
	racereleaseacquireg(getg(), addr)
}

// go nosplit 
func racereleaseacquireg(gp *g, addr unsafe.Pointer) {
	if getg().raceignore != 0 || !isvalidaddr(addr) {
		return
	}
	racecall(&__tsan_release_acquire, gp.racectx, uintptr(addr), 0, 0)
}

func racereleasemerge(addr unsafe.Pointer) {
	racereleasemergeg(getg(), addr)
}

func racereleasemergeg(gp *g, addr unsafe.Pointer) {
	if getg().raceignore != 0 || !isvalidaddr(addr) {
		return
	}
	racecall(&__tsan_release_merge, gp.racectx, uintptr(addr), 0, 0)
}

func racefingo() {
	racecall(&__tsan_finalizer_goroutine, getg().racectx, 0, 0, 0)
}

// 包中声明。

// go:linkname-abigen_-sync_-atomic_-LoadInt32-sync/atomic。LoadInt32 
func abigen_sync_atomic_LoadInt32(addr *int32) (val int32)

// go:linkname abigen_sync_atomic_LoadInt64 sync/atomic。LoadInt64 
func abigen_sync_atomic_LoadInt64(addr *int64) (val int64)

// go:linkname abigen_sync_atomic_LoadUint32 sync/atomic。LoadUint32 
func abigen_sync_atomic_LoadUint32(addr *uint32) (val uint32)

// go:linkname abigen_sync_atomic_LoadUint64 sync/atomic。LoadUint64 
func abigen_sync_atomic_LoadUint64(addr *uint64) (val uint64)

// go:linkname abigen_sync_atomic_loaduintptpr sync/atomic。loaduintpttr 
func abigen_sync_atomic_LoadUintptr(addr *uintptr) (val uintptr)

// go:linkname abigen_sync_atomic_LoadPointer sync/atomic。LoadPointer 
func abigen_sync_atomic_LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)

// go:linkname abigen_sync_atomic_StoreInt32 sync/atomic。StoreInt32 
func abigen_sync_atomic_StoreInt32(addr *int32, val int32)

// go:linkname abigen_sync_atomic_StoreInt64 sync/atomic。StoreInt64 
func abigen_sync_atomic_StoreInt64(addr *int64, val int64)

// go:linkname abigen_sync_atomic_StoreUint32 sync/atomic。StoreUint32 
func abigen_sync_atomic_StoreUint32(addr *uint32, val uint32)

// go:linkname abigen_sync_atomic_StoreUint64 sync/atomic。StoreUint64 
func abigen_sync_atomic_StoreUint64(addr *uint64, val uint64)

// go:linkname abigen_sync_atomic_SwapInt32 sync/atomic。SwapInt32 
func abigen_sync_atomic_SwapInt32(addr *int32, new int32) (old int32)

// go:linkname abigen_sync_atomic_SwapInt64 sync/atomic。SwapInt64 
func abigen_sync_atomic_SwapInt64(addr *int64, new int64) (old int64)

// go:linkname abigen_sync_atomic_SwapUint32 sync/atomic。SwapUint32 
func abigen_sync_atomic_SwapUint32(addr *uint32, new uint32) (old uint32)

// go:linkname abigen_sync_atomic_SwapUint64 sync/atomic。SwapUint64 
func abigen_sync_atomic_SwapUint64(addr *uint64, new uint64) (old uint64)

// go:linkname abigen_sync_atomic_AddInt32 sync/atomic。AddInt32 
func abigen_sync_atomic_AddInt32(addr *int32, delta int32) (new int32)

// go:linkname abigen_sync_atomic_AddUint32 sync/atomic。AddUint32 
func abigen_sync_atomic_AddUint32(addr *uint32, delta uint32) (new uint32)

// go:linkname abigen_sync_atomic_AddInt64 sync/atomic。AddInt64 
func abigen_sync_atomic_AddInt64(addr *int64, delta int64) (new int64)

// go:linkname abigen_sync_atomic_AddUint64 sync/atomic。AddUint64 
func abigen_sync_atomic_AddUint64(addr *uint64, delta uint64) (new uint64)

// go:linkname abigen_sync_atomic_adduintpttr sync/atomic。adduintpttr 
func abigen_sync_atomic_AddUintptr(addr *uintptr, delta uintptr) (new uintptr)

// go:linkname abigen_sync_atomic_CompareAndSwapInt32 sync/atomic。CompareAndSwapInt32 
func abigen_sync_atomic_CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)

// go:linkname abigen_sync_atomic_CompareAndSwapInt64 sync/atomic。CompareAndSwapInt64 
func abigen_sync_atomic_CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)

// go:linkname abigen_sync_atomic_CompareAndSwapUint32 sync/atomic。CompareAndSwapUint32 
func abigen_sync_atomic_CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)

// go:linkname abigen_sync_atomic_CompareAndSwapUint64 sync/atomic。比较ADSWAPUINT64 
func abigen_sync_atomic_CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
